web开发

原型设计服务:墨刀网**

Java Web知识体系大纲

[TOC]

0 前言

1 JAVA WEB

1.1 http协议

1.2 servlet技术

1.3 会话技术(Cookie&Session)

1.3.1 客户端会话技术

1.3.2 服务器端会话技术

1.4 jsp技术

1.4.1 jsp技术基础

1.4.1.1 jsp原理
1.4.1.2 jsp指令
1.4.1.3 jsp脚本片段
1.4.1.4 jsp表达式

1.4.2 el表达式

el表达式(expression language,el),

  • 可以轻松访问存放在域对象中的bean对象及属性
  • 结合JSTL,可以轻松访问集合中的元素
  • 可以做简单的逻辑判断
  • 调用java方法
1.4.2.1 读取数据
  1. 读取基本数据类型
<%-- 存放基本数据类型到request域--%>
<%
    String data="abcd";
    request.setAttribute("data",data);
%>
<%-- 使用el从request中取得数据--%>
存放的数据是:${data}
  1. 读取对象类型

    ①简单对象

<%-- 
    存放对象类型数据类型到request域
    Person类:
        -String:name
        —int:age
--%>
<%
    Person p = new Person();
    request.setAttribute("person",p);
%>
<%-- 使用el从request中取得数据--%>
存放person对象及其属性:${person.name} ${person.age}

​ ②复杂对象:存在对象聚合

<%-- 
    存放复杂对象类型数据类型到request域
    Address类:
        —String: city
        —String: province 
    Person类:
        -String:name
        —int:age
        -Address:address
--%>
<%
    Person p = new Person();
    p.setName("lr");
    p.setAge(24);
    Address a = new Address();
    a.setProvince("Shanghai"); // 创建地址
    p.setAddress(a);           // 地址赋值给person
    request.setAttribute("person",p);
%>
<%-- 使用el从request中取得数据--%>
存放person对象及其属性:    ${person.name} ${person.age} 
                      ${person.address.province}
                      ${person.address.city}
  1. 读取List集合
<%
    List list = new ArrayList();
    list.add(new Person("john"));
    list.add(new Person("peter"));
    list.add(new Person("andrew"));
    request.setAttribute("list",list);
%>
<%-- 使用el从request中取得数据--%>
    ${list[0].name}  ${list[1].name}
  1. 读取Map集合
<%
    Map map = new HashMap();
    map.put("aa",new Person("john"));
    map.put("bb",new Person("andrew"));
    map.put("cc",new Person("peter"));
    map.put("111",new Person("lucy"));
    request.setAttribute("m",map);
%>
<%-- 使用el从request中取得数据--%>
    ${map["aa"].name}  ${map["bb"].name} ${map["cc"].name}
    ${map.aa.name} ${map.bb.name} ${map.cc.name}
<!-- 如果关键字是数字开头,必须用下面写发-->
<!-- 使用el表达式取数据时候,通常用.号,如果.号取不出来,则用[]号 -->
    ${map["111"].name}  
  1. 访问指定域对象的数据及其他web对象
${pageScope.user.name}
${requesetScope.user.name}
${sessionScoope.user.name}
${applicationScope.user.name}

<%-- 获取客户端请求参数,param是一个Map对象,--%>
<%--其中每个请求参数给定一个值 --%>
<%-- http://localhost:8080/login.jsp?username=aa & password=123 --%>
${param}           
${param.username} ${param.password}

<%-- 获取客户端请求参数,paramValues是一个Map对象,--%>
<%-- 其中每个请求参数给定多个值 --%>
<%-- http://localhost:8080/login.jsp?username=liuyun & username=rongbo --%>
${paramValues}    
${paramValues.username[0]}
${paramValues.username[1]}

${header}          
${header.Host}  ${header['Accept-Language']}
${headerValues}   

<%--cookie对象是一个Map对象,存放的是‘关键字映射到Cookie对象’的entry --%>
${cookie}          <%-- Map对象 --%> 
${cookie.JSESSIONID.name}
${cookie.JSESSIONID.vlaue}

<%--web.xml中配置了参数 --%>
<%-- 
    <context-param>
        <param-name>db</param-name>
        <param-value>url-db</param-value>
    </context-param>
--%>
${initParam}       
${initParam.db}
1.4.2.2 逻辑判断
<%--完成数据回显,大量使用二元表达式--%>
<%--radio表单回显--%>
<% 
    request.setAttribute("gender", "male");
%>
<input type="radio" name="gender" value="male" checked=${gender=='male'?'checked':''}/>
<input type="radio" name="gender" value="female" checked=${gender=='female'?'checked':''} /> 

<%--checkbox表单回显--%>

<%--判断list集合是否为空--%>
${empty(list)}  
1.4.2.3 *调用java代码

1.4.3 jsp标签库JSTL

  1. 导包:jstl standard
  2. 使用jsp指令,导入jstl的uri,并指定前缀: <%@taglib uri="#" prefix="c"/>

    : 进入standard.jar->meta-inf: c.tld文件中,描述表述库文件

<%@taglib uri="#"    prefix="c"/>
<%------------------------------------------------------%>
<%--迭代map集合中的数据--%>
<%------------------------------------------------------%>
<%
    List list = new ArrayList();
    list.add(new Person("john"));
    list.add(new Person("peter"));
    list.add(new Person("andrew"));
    request.setAttribute("list",list);
%>
<c:forEach var="person" items="${list}">
    ${person.name};
</c:forEach>

<%------------------------------------------------------%>
<%--迭代map集合中的数据--%>
<%------------------------------------------------------%>
<%
    Map map = new HashMap();
    map.put("aa",new Person("john"));
    map.put("bb",new Person("andrew"));
    map.put("cc",new Person("peter"));
    map.put("111",new Person("lucy"));
    request.setAttribute("m",map);
%>
<%-- 对Map集合,本质上是对Map.entrySet放回的集合进行迭代--%>
<c:forEach item="entry" items="${map}">
    ${entry.key}:${entry.value.name}
</c:forEach>

<%------------------------------------------------------%>
<%--测试条件是否成立--%>
<%------------------------------------------------------%>
<c:if test="${user!=null}">
    欢迎您${user.username}
</c:if>
<c:if test="${user==null}">
    <input type="text" name="username"/>
    <input type="password" name="password"/>
    <input type="submit" value="登录"/>
</c:if>

1.4.4 jsp自定义标签库

1.5 WEB开发模式

1.5.1 Model1(Jsp+JavaBean)

1.5.2 Model2(JSP+Servlet+JavaBean)

1.5.3 WEB三层架构

1.5.3.1 概述
1.5.3.2 web层

web三层架构充分借鉴了MVC设计模式,优化程序结构,其中web层包括了:

  1. web层控制器servlet,控制器servlet调用业务逻辑层代码完成业务逻辑,不同的业务有不同的控制器
  2. web层控制jsp的servlet,通过接受客户端请求,同利用请求转发技术到jsp页面,从而返回web页面
  3. web层还包括web层工具类,负责从request请求中获得参数数据,
1.5.3.2.1 隐藏jsp的servlet
1.5.3.2.2 控制器servlet
1.5.3.3 service层
1.5.3.4 dao层

1.5.4 “MVC设计模式”和“WEB三层架构”之概念浅析

1.5.5 “前台、后台”和“前端、后端”概念浅析

2 SSH&SSM

2.1 概述

2.1 Struts2

2.2 Hibernates

2.3 Spring4

2.4 springMVC

2.5 MyBaits

2.6 SSH框架整合(Struts2+Spring+Hibernate)

2.7 SSM框架整合(Struts2+SpringMVC+MyBaits)

3 MySql

3.1 安装和配置

3.1.1 安装

Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。

3.1.2 配置

3.2 SQL语言

3.2.1 DDL

3.2.1.1 库操作
  1. 创建库
/*
 * CREATE DATABASE [IF NOT EXISTS] db_name [[create_specification] 
 *                                        [,create_specification]...]
 * create_specification:
 *     [DEFAULT] CHARACTER SET charset_name | [DEFAULT] COLLATE collation_name
 */
 create database mydb1;
 
 create database mydb2 character set utf8; -- 指定字符集,utf8, 不是utf-8

 create database mydb2 character set utf8 collate utf8_general_ci; --指定字符集、排序规则
 
 show create database mydb2;  --查看创建库的细节
  1. 删除库
drop database mydb1;
  1. 修改库
/*
/*
 * CREATE DATABASE [IF NOT EXIST] db_name [[alter_specification] 
 *                                        [,alter_specification]...]
 * alter_specification:
 *     [DEFAULT] CHARACTER SET charset_name | [DEFAULT] COLLATE collation_name
 * 注意:不能修改库名
 */
 alter database mydb2 character set utf8;
 show create database mydb2;
  1. 备份库

mysqldump -u 用户名 -p 数据库名 > 文件名.sql (windows命令)

  1. 恢复库

第一种方法

/**
 * source 文件名.sql 
 */
 create database tt;
 user tt;
 create table a{
     name varchar(20) 
 };
 insert into a(name) values('aaaa');
 select * from a;

mysql -u root -p tt > c:tt.sql (window命令 导出)

drop dababase tt; --删除库
--恢复库,只能恢复数据,不能恢复库,因此必须重新新建库
--1.创建库
create database tt;  --建库
user tt;             --进入库tt
source c:\a.sql;     --恢复数据

第二种方法

mysql -uroot -proot tt<c:a.sql (windows命令)

3.2.1.2 表操作
  1. 创建表
/* CREATE TABLE table_name
 * {
 *    field1 datatype,
 *    filed2 datatype,
 *    filed3 datatype
 * }character set charset_name collate collation_name;
 * 
 * datatype:
 * 文本、二进制:
 *            char(size)            ------定长
 *            varchar(size)         ------变长
 *            blob(最大64k)   longblob -----变长
 *            text    longtext          -----变长,大文本
 * 日期时间:date  datetime timestamp   -----变长
 
 * 注意:实际开发过程中,容量很大的数据(比如音频、视频等)不会存放到数据库中,而是存放到文件系统。
 * 原因:解决数据库链接资源。读取超大容量数据,连接占用的时间长。
 */
 create table employee
 {
     id int,
     name varchar(40),
     sex varchar(4),
     entry_date date,
     job varchar(40),
     salary decimal(8,2),
     resume text
 };
 show tables;                ----查看所有表
 show create table employee;----显示指定表的创建细节
 desc employee ;            ----查看表结构 
  1. 修改表
/* 
 * 1.修改表:增加列、修改列数据类型、删除列、修改列名
 * ALTER TABLE table_name 
 *         ADD     column datatype [default_expr] [,column datatype]...;
 *         MODIFY  column datatype [default_expr] [,column datatype]...;
 *         DTOP    column;
 *        CHANGE COLUMN old_name new_name data_type; 
 * 2. 修改表名    
 * RENAME TABLE table_name to table_name_1
 *
 * 3. 修改表的字符集
 * ALTER TABLE table_name character set utf8
 * 
 * 4. 删除表
 * DROP TABLE table_name;
 */
 alter table employee add image blob;----增加大头贴列,存放大头贴图片
 alter table employee modify job varchar(60);----修改job列
 alter table employee drop sex;----删除类
 rename table employee; ----重新命名表(库不能重命名,但是表可以)
 alter table employee character utf8;----修改字符集
 alter table employee change column name username varchar(30);----修改列名
  1. 删除表
drop table employee;----删除表

3.2.2 DML(crud之cud操作)

crud: crete read update delete

  1. insert(create)
/**
 * INSERT INTO tb_name[(filed1[, field2...])]
 * VALUES(value [,value...]);
 *
 * 细节:1. 表名后面的字段列表可以不跟,这种情况下,values必须按顺序指定每个字段的值
 *        2. 字符和日期必须被单引号''包含
 *      3. 插入空值:不指定值,或者指定为null
 *        4. insert into user(id) values(4)和insert into user(id) values('4')
 *            因此,所有的数值类型的值可以加单引号,mysql可以自动转换为相应类型的值
 */         
RENAME TABLE employee to user;
----注意没有TABLE关键字
insert into user(id, username,birthday, entry_date, job, salary,resume) 
          values(1, 'andrew','2014-03-33','bb','2019-06-32',90,'aaaa'); 
  1. update
/** 
 * UPDATE tb_name 
 * SET col_name1=expr1 [,col_name2=expr2...]
 * [WHERE where_definition]
 */
 update employee set salary=3000 where name='张三';
 update employee set salary=1000,job='ccc' where name='andrew';
  1. delete
/** 
 * DELETE from tb_name 
 * [WHERE where_definition]
 * 注意:
 *    1.delete只能以记录为单位删除;
 *    2.从一个表中删除记录将引起其他表的参照完整性问题。在修改数据库中的数据时,
 *      头脑中应时刻不要忘记这个潜在的问题
 */
 delete from employee where name="andrew";
 delete from employee;     ----删除所有记录
 truncate table employee;  ----摧毁表,并重新构建表结构,速度快,在要删除所有数据记录的情形下

3.2.3 DQL(crud之r)

select(read),包括:select子句、where子句、from子句、order by子句、group by子句、having子句

使用source命令导入sql脚本

/** 
 * SELECT [DISTINCT] *[column1 [,column2...]]  FROM tb_name;
 */
 
 ----@file:定义sql脚本:c:\student.sql(可以是其他目录)
 create table student
 {
     id int, 
     name varchar(20),
     chinese float,
     english float,
     math float
 };
 insert into student(id,name,chinese,english,math) values('1','andrew','22','90','97');
 insert into student(id,name,chinese,english,math) values('2','peter','100','90','97');
 insert into student(id,name,chinese,english,math) values('3','lily','67','90','97');
 insert into student(id,name,chinese,english,math) values('4','lucy','33','90','97');
 
 ----在客户端,使用: source  c:\student.sql
 
 ----查询
 select * from student;                    ----查询所有
 select name,english from student;        ----查询感兴趣的字段
 select distinct english from student;    ----剔除重复数据

在select子句中使用表达式

/** 
 * SELECT   * {column1 | expression, column2 | expression,...}
 * FROM tabble;
 *
 * SELECT column as 别名 from table;
 */
 select name,(chinese+english+math) from student;             ----计算总分
 select name as 姓名,(chinese+english+math) as 分数 from student; ----添加别名
 select name 姓名,(chinese+english+math) 分数 from student; ----添加别名
 select *  from student where english>'90';
 select *  from student where name='andrew';
 select *  from student where (chinese+english+math)>'200';

where子句中使用运算符

/** 
 * 在where子句中使用运算符
 * 1.比较运算:
 *        >  >=  <  <=  =  <>
 *         BETWEEN ... AND ...  
 *      IN(set)
 *      LIKE 'pattern' ,这里使用两种通配符,%匹配一个或者多个字符,_匹配单个字符
 *      IS NULL
 * 2.逻辑运算:
 *        and 
 *        or 
 *        not
 */
select * from student where english>'80' and english<'90';----(80,90)
select * from student where english between '80' and '90'; ----[80,90]
select * from student where math in(80,90);
select * from student where math='80' or math='90';
select * from student where name like '李%';
select * from student where math>'80' and chinese>'80';

使用order by子句排序

/** 
 * 使用order by 子句
 *
 * SELECT   column1,column2...
 * FROM tabble 
 * ORDER BY column ASC|DESC;
 */
 select name,math from student order by math desc;
 select name, (chinese+english+math) as score from student order by score desc;

使用聚合函数

/**
 * 使用聚合函数:count,sum, avg, max, min
 * SELECT count(*) | count(列名) 
 * FROM table
 * [WHERE where_definition];
 */
 select count(*) from student; ----count聚合函数只会统计有值的数据
 select sum(english), sum(math) from student;
 select sum(english)/sum(*) from student;
 select avg(math) from student;

使用group by子句

select  product, sum(price)  from orders group by product;

使用having子句: 类似于where子句,但是where子句后不能跟聚合函数,但是having可以

select  product from orders group by product having sum(product)>'100';

4 web开发典型业务逻辑

4.1 注册登录

使用mvc设计模式,结合web三层架构思想,开发注册、登录模块。具体到项目代码包组织如下:

domain

dao

service

web

——web.ui:hide jsp pages for users

——web.controller:calling service layer

——web.formbean: from jsp pages to controller

utils

Title:用户注册\n业务流程
浏览器->web.UI.\nRegisterUiServlet:访问注册页面\nregister.jsp
web.UI.\nRegisterUiServlet->register.jsp:forward到\n/WEB-INF/jsp/register.jsp
register.jsp->浏览器:返回register.jsp\n生成的注册页面
浏览器->RegisterServlet:用户填写表单,\n提交到RegisterServlet
RegisterServlet->WebUtils:封装request\n请求参数到Bean
WebUtils->WebUtils:调用BeanUtils.\ncopyProperty\n(destBean,key,value);
WebUtils->RegisterServlet:返回FormBean
RegisterServlet->RegisterServlet:form .\nvalidate
RegisterServlet->WebUtils:调用BeanUtils.\ncopyBean\n(key,value);
WebUtils->RegisterServlet:返回User \ndomain对象
RegisterServlet->BusinesService\nServlet:注册
BusinesService\nServlet->BusinesService\nServlet:1.检查用户\n是否存在\n2.不存在\则注册\n3.存在\n返回错误信息
BusinesService\nServlet->浏览器:返回login.jsp\n生成的登录页面

4.3 验证码

4.4 购物车

/**
 * 数据库,
 * 1. 使用Map集合模拟数据库;
 * 2. 初始数据通过静态代码块添加到内存中Map集合
 */
package cn.itcast.DB;
import java.util.LinkedHashMap;
import java.util.Map;
import cn.itcast.domain.Book;
public class DB {
    private static Map map = new LinkedHashMap<String,Book>();
    static{
        map.put("1", new Book("1","java","lr","itcast",33.3f));
        map.put("2", new Book("2","php","lr","itcast",33.3f));
        map.put("3", new Book("3","spring","lr","itcast",33.3f));
        map.put("4", new Book("4","struts","lr","itcast",33.3f));
        map.put("5", new Book("5","hibernate","lr","itcast",33.3f));
    }
    
    public static Map getAll(){
        return map;
    }
}
/**
 * DAO层:
 */
import java.util.LinkedHashMap;
import java.util.Map;
import cn.itcast.DB.DB;
import cn.itcast.domain.Book;
public class BookDao {
    public Map getAll(){
        return DB.getAll();
    }
    public Book find(String id){
        return (Book) DB.getAll().get(id);
    }
}
/**
 * 实体类:包括Book、Cart、CartItem
 */
package cn.itcast.domain;
public class Book {
    String id;
    String name;
    String author;
    String description;
    float price;
    public Book(String id, String name, String author, String description,float price) {
        super();
        this.id = id;
        this.name = name;
        this.author = author;
        this.description = description;
        this.price = price;
    }
    /* 此处省略getters和setters方法
}
package cn.itcast.domain;
public class CartItem {
    private Book book;
    int quantity;
    float price;
}
package cn.itcast.domain;
import java.util.LinkedHashMap;
import java.util.Map;
public class Cart {
    private Map<String, CartItem> map = new LinkedHashMap();
    private float price;
    public void add(Book book){
        CartItem item = map.get(book.getId());
        if(item == null){
            item = new CartItem();
            item.setBook(book);
            item.setQuantity(1);
            map.put(book.getId(), item);
        }else{
            item.setQuantity(item.getQuantity()+1);
        }
    }
    public Map<String, CartItem> getMap() {
        return map;
    }
    public void setMap(Map<String, CartItem> map) {
        this.map = map;
    }
    public float getPrice() {
        float totalPrice = 0.0f;
        
        for(Map.Entry<String, CartItem> entry: map.entrySet()){
            totalPrice += entry.getValue().getPrice();
        }
        this.price = totalPrice;
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
}
/**
 * 业务逻辑层:
 */
package cn.itcast.serviceimpl;
import java.util.Map;
import cn.itcast.daoimpl.BookDao;
import cn.itcast.domain.Book;
import cn.itcast.domain.Cart;
public class BusinessService {
    BookDao dao = new BookDao();
    public Map getAll(){
        return dao.getAll();
    }
    public Book find(String id){
        return dao.find(id);
    }
    public void deleteCartItem(String id, Cart cart) {
        // TODO Auto-generated method stub
        cart.getMap().remove(id);
    }
    public void clearCart(Cart cart) {
        // TODO Auto-generated method stub
        cart.getMap().clear();
    }
    public void changeItemQuantity(String id, int quantity, Cart cart) {
        // TODO Auto-generated method stub
        cart.getMap().get(id).setQuantity(quantity);
    }
}
/**
 * web层——控制器servlet
 * @brief:
 *        1. web层控制器是页面请求的web资源,控制器调用逻辑层进行处理,将处理结果结果转发到jsp;
 *        2. 转发到的jsp中,使用jstl、el表达式将数据从域中取出来用于显示;
 *        3. jsp页面中的javascript代码和用户交互,根据结果动态请求其他web资源
 *        包括的Servlet:
 *                 ListBookServlet            对应‘浏览商品’链接访问的资源
 *                 BuyServlet                 对应‘购买’链接对应的资源
 *                 ChangeQuantityServlet      对应‘数量input组件’对应的请求的资源
 *                 DeleteCartItemServlet      对应‘删除’链接对应的资源
 *                 ClearCartServlet           对应‘清空购物车’链接对应的资源
 */
 // 具体servlet类省略
<%-- 浏览商品页面 --%>
    <h1>书籍列表</h1>
    <table border="1" width="70%" align="center">
        <tr>
            <td>书名</td>
            <td>作者</td>
            <td>简介</td>
            <td>价格</td>
            <td>操作</td>
        </tr>
        <c:forEach var="entry" items="${map }">
            <tr>
                <td>${entry.value.name }</td>
                <td>${entry.value.author }</td>
                <td>${entry.value.description }</td>
                <td>${entry.value.price }</td>
                <td>
                    <a href="${pageContext.request.contextPath }/BuyServlet?id=${entry.value.id }" target="_blank">购买</a>
                </td>
            </tr><br/>
        </c:forEach>
    
    </table>
<%--购物车页面--%>
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>


<script type="text/javascript">
    function deleteItem(id){
        var b = window.confirm("您确定删除吗?");
        if(b){
            window.location.href=href="${pageContext.request.contextPath }/DeleteItemServlet?id="+id;
        }
    }
    function clearcart(){
        var b = window.confirm("您确定清空吗?");
        if(b){
            window.location.href="${pageContext.request.contextPath }/ClearCartServlet";
        }
    }
    function changeQuantity(input, id, oldquantity){
        var quantity = input.value;
        
        if(isNaN(quantity)){
            alert("请输入合法数字");
            input.value = oldquantity;
            return;
        }
        
        if(quantity < 0 || quantity != parseInt(quantity) ){
            alert("请输入正整数");
            input.value = oldquantity;
            return;
        }
        
        var b = window.confirm(" 确认修改吗为"+quantity);
        if(b){
            window.location.href="${pageContext.request.contextPath}/ChangeQuantityServlet?id="+id+"&quantity="+quantity;
        }
        
    }
</script>

</head>
<body style="text-align:center;">
    <h1>书籍列表</h1>
    <c:if test="${empty(cart.map)}">
        您没有购买任何商品
    </c:if>
    <c:if test="${!empty(cart.map)}">
    <table border="1" width="70%" align="center">
        <tr>
            <td>书名</td>
            <td>作者</td>
            <td>单价</td>
            <td>数量</td>
            <td>小计</td>
            <td>操作</td>
        </tr>
        <c:forEach var="entry" items="${cart.map }">
            <tr>
                <td>${entry.value.book.name }</td>
                <td>${entry.value.book.author }</td>
                <td>${entry.value.book.price }</td>
                <td>
                    <input type="text" name="quantity" value="${entry.value.quantity }"
                    onchange="changeQuantity(this,${entry.key },  ${entry.value.quantity })"/>
                    
                </td>
                <td>${entry.value.price }</td>
                <td>
                    <a href="javascript:vid(0)" onclick="deleteItem(${entry.key})">删除</a>
                </td>
        </c:forEach>
        <tr>
            <td colspan="3">总价</td>
            <td colspan="2">${cart.price}</td>
            <td colspan="1">
                <a href="javascript:vid(0)" onclick="clearcart()">清空</a>
            </td>
        </tr>
    
    </table>
    </c:if>
</body>
</html>

4.5 在线支付

附录

关键代码

1 DAO层:dom4j操作xml的工具类

/**
 * 这里导报必须导入dom4j的document类
 * @author lr
 *
 */
public class XmlUtils {
    private static String xmlPath = null;
    static{
        xmlPath = XmlUtils.class.getClassLoader().getResource("users.xml").getPath();
        System.out.println(xmlPath);
    }
    
    
    public static Document getDocument() throws DocumentException{
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File(xmlPath));
        return document;
    }
    
    public static void write2Xml(Document document) throws IOException{
            XMLWriter writer = new XMLWriter(
                new FileWriter( xmlPath)
            );
            writer.write( document );
            writer.close();
    }
}

2 Service层:生成md5码

/**
 * 1.使用消息摘要算法生成md5码,然后使用base64算法编码
 * 2.md5码生成采用消息摘要算法类 MessageDigest
 * 3.生成base64码,采用 Base64
 */
public class ServiceUtils {
    public static String md5(String data){
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            byte[] md5 = md.digest(data.getBytes());
            /*
             * md5摘要太长,采用base64进行编码
             * 1.使用BASE64Encoder,but jdk not support this deprecated class and method
             * 2.使用Base64来获得Encoder
             */
            Base64.Encoder encoder = Base64.getEncoder();
            return encoder.encodeToString(md5);
            
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

3 Web层:request中的form表单数据封装到formbean;frombean->domain bean

/**
 * @method:public static <T> T request2Bean(HttpServletRequest request, Class<T> cls)
 * @brief:
 *  第一个关键点;将request中的property拷贝到bean中去,要使用到beanutils包中的静态方法,拷贝特定属性
 * <T>是类型参数的形式参数,调用过程中类型通过T传入
 * @author lr
 * 
 * 关键点:使用BeanUtils的copyProperties时,之能拷贝bean里面的基本数据类型,要将form中的String日期
 *        拷贝到Domain bean的Date属性中去,必须要写转换器
 *        ConvertUtils.register(Converter c,Class cls)
 */
public class WebUtils {
    public static <T> T request2Bean(HttpServletRequest request, Class<T> cls) {
        // 1.create an T instance
        T bean;
        try {
            bean = cls.newInstance();
            
            // 2. copy propertys in request to new bean
            Enumeration<String> e = request.getParameterNames();
            while(e.hasMoreElements()){
                String name = e.nextElement();
                String value = request.getParameter(name);
                BeanUtils.copyProperty(bean, name,value);
            }
            
        } catch (Exception e) {
            throw new RuntimeException();
        }
        return bean;
    }
    public static String generatieID(){
        return UUID.randomUUID().toString();
    }
    public static void copyBean(Object src, Object dest){
        ConvertUtils.register(new Converter() {
            
            public Object convert(Class type, Object value) {
                // TODO Auto-generated method stub
                if(value==null){
                    return null;
                }
                
                String str = (String)value;
                if(str.equals(""))
                    return null;
                
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    return df.parse(str);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    throw new RuntimeException(e);
                }
            
            }
        }, Date.class);
        try {
            BeanUtils.copyProperties(dest, src);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw new RuntimeException(e);
        } 
    }
}

4 使用dom4j搜索xml节点的关键用法

/**
 * xpath常见模式:
 * 1.查找属性值为指定值的user节点:
 *    "//user[@username='"+username+"' and @password='"+password+"']" 用户名、密码为指定值
 *    "//user[@username='"+username+"']" 用户名为指定值
 */
public class UserDaoImpl {
    public void add(User user){
        try {
            Document document = XmlUtils.getDocument();
            
            /*
             * get the root element
             */
            Element root = document.getRootElement();
            Element e = root.addElement("user");
            e.setAttributeValue("id",user.getId());
            e.setAttributeValue("username", user.getUsername());
            e.setAttributeValue("password", user.getPassword());
            e.setAttributeValue("birthday", user.getBirthday() == null?"":user.getBirthday().toLocaleString());
            XmlUtils.write2Xml(document);
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /*
     * find user according to specified usenrmae and password
     */
    public User find(String username, String password){
        User user = null;
        try {
            Document document = XmlUtils.getDocument();
            Element e = (Element)document.selectSingleNode(
                    "//user[@username='"+username+"' and @password='"+password+"']");
            if(e == null)
                return null;
            user = new User();
            user.setId(e.attributeValue("id"));
            user.setUsername(e.attributeValue("username"));
            user.setPassword(e.attributeValue("password"));
            user.setEmail(e.attributeValue("email"));
            user.setBirthday(new Date());
            
            
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return user;
    }
    /*
     * find if user exist
     */
    public boolean find(String username){
        try {
            Document document = XmlUtils.getDocument();
            Element e = (Element)document.selectSingleNode("//user[@username='"+username+"']");
            if(e == null)
                return false;
            
        } catch (DocumentException e) {
            // TODO Auto-generated cach block
            e.printStackTrace();
        }
        return true;
    }
}

5 formbean中的验证算法(正则表达式)

   /**
    * 正则表达式的\w在java字符串中,写成\\w; 
    * 典型的模式:
    * 1.邮箱:"\\w+@\\w+(\\.\\w+)+",其中\\w表示字母、数字、下划线,例如lr@whu.edu.cn
    * 2.用户名3-8个字母:"[a-zA-Z]{3,8}"
    * 3.密码3-8位字母:"\\d{3,8}"
    *
    */
    public boolean validate(){
        boolean isOK =true;
        /*
         * username
         * 不允许为空,因此必须加trim,因为""和"    "是等同,因此用trim修剪空格
         */
        if(this.username == null || this.username.trim().equals("")){
            isOK = false;
            errs.put("username", "username can not be empty");
        }else{
            if(!username.matches("[a-zA-Z]{3,8}")){
                isOK = false;
                errs.put("username", "用户名必须是3-8位字母");
            }
        }
        
        /*
         * password
         * 不允许为空,因此必须加trim,因为""和"    "是等同,因此用trim修剪空格
         */
        if(this.password == null || this.password.trim().equals("")){
            isOK = false;
            errs.put("password", "password can not be empty");
        }else{
            if(!password.matches("\\d{3,8}")){
                isOK = false;
                errs.put("password", "password must be 3-8 digits");
            }
        }
        /*
         * password2
         * 不允许为空,因此必须加trim,因为""和"    "是等同,因此用trim修剪空格
         */
        if(this.password2 == null || this.password2.trim().equals("")){
            isOK = false;
            errs.put("password2", "password2 can not be empty");
        }else{
            if(!password.equals(password2)){
                isOK = false;
                errs.put("password2", "password2 not equals passwords");
            }
        }
        /*
         * email
         * 不允许为空,因此必须加trim,因为""和"    "是等同,因此用trim修剪空格
         */
        if(this.email == null || this.email.trim().equals("")){
            isOK = false;
            errs.put("email", "email can not be empty");
        }else{
            if(!email.matches("\\w+@\\w+(\\.\\w+)+")){
                isOK = false;
                errs.put("email", "not the correct email format");
            }
        }
        /**
         * birthday can be empty,but if not empty ,it must be al valid value
         */
        if(!(this.birthday== null) && !this.birthday.trim().equals("")){
            try{
                DateLocaleConverter dlc = new DateLocaleConverter();
                dlc.convert(this.birthday,"yyyy-MM-dd");
            }catch(ConversionException e){
                isOK = false;
                errs.put("birthday", "format is invalid");
            }
        } 
        return isOK;
    }

6 使用UUID生唯一ID

    public static String generatieID(){
        return UUID.randomUUID().toString();
    }

7 String到Date的转换

/**
 * birthday can be empty,but if not empty ,it must be al valid value
 *
 * DateLocaleConverter 和 SimpleDateFormat
 *
 * 1. 使用DateLocaleConverter,convert方法转换非法字符串抛出异常
 * 2. 确定字符串表示的日前是合法日期前提下,可以使用SimpleDateFormat
 */
if(!(this.birthday== null) && !this.birthday.trim().equals("")){
    try{
        DateLocaleConverter dlc = new DateLocaleConverter();
        // 利用convert方法抛异常的特性,验证参数合法性
        dlc.convert(this.birthday,"yyyy-MM-dd"); 
    }catch(ConversionException e){
        isOK = false;
        errs.put("birthday", "format is invalid");
    }
} 

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
    return df.parse(str);    // parse字符串
} catch (Exception e) {
    // TODO Auto-generated catch block
    throw new RuntimeException(e);
}

mysql客户端乱码问题

插入数据乱码

问题描述:数据库为采用utf8字符集,在客户端插入中文数据,显示插入错误

原因分析:客户端默认采用gb2312字符集,数据库采用的非gb2312,客户端输入发送给数据库

解决思路:告诉数据库客户端采用gb2312编码

myql>show variables like 'chara%'
mysql>set character_set_client=gb2312;
mysql>insert into employee(username) values('张三');
myql>select * from employee;

取出数据乱码

问题描述:数据库采用utf字符集,客户端正确插入了中文数据到表中,在客户端查询时输出为乱码

原因分析:数据库按照utf8查询到了数据,送到客户端,但是客户端以gb2312解析后显示

解决思路:要想查看时不乱码

myql>show variables like 'chara%';
myql>set character_set_results=gb2312;
myql>select * from employee;

配置客户端永久不显示乱码

修改安装目录下的my.ini文件,CLIENT SECTION部分的:default-character-set=gb2312

#修改配置文件
#修改安装目录下的my.ini文件,
#CLIENT SECTION部分的:default-character-set=utf8
#省略
# CLIENT SECTION
# ----------------------------------------------------------------------
#
# The following options will be read by MySQL client applications.
# Note that only client applications shipped by MySQL are guaranteed
# to read this section. If you want your own MySQL client program to
# honor these values, you need to specify it as an option during the
# MySQL client library initialization.
#
[client]
port=3306

[mysql]
default-character-set=utf8

# SERVER SECTION
# ----------------------------------------------------------------------
#
# The following options will be read by the MySQL Server. Make sure that
# you have installed the server correctly (see above) so it reads this 
# file.
#
[mysqld]
# The TCP/IP Port the MySQL Server will listen on
port=3306

#Path to installation directory. All paths are usually resolved relative to this.
basedir="D:/Program Files (x86)/MySQL/MySQL Server 5.0/"

#Path to the database root
datadir="D:/Program Files (x86)/MySQL/MySQL Server 5.0/Data/"

# The default character set that will be used when a new schema or table is
# created and no character set is defined
default-character-set=utf8

#省略

流云的博客
3 声望1 粉丝

山高月小 水落石出